package controllers

import (
	"beego/comm/auth"
	"beego/comm/db"
	"beego/comm/requests"
	"beego/comm/source"
	"beego/comm/utils"
	"encoding/json"
	"fmt"
	"strings"

	"github.com/astaxie/beego"
)

type MathCalcController struct {
	beego.Controller
}

func (c *MathCalcController) EqCalc() {
	beego.Info("================= EqCalc start =================")
	result := map[string]interface{}{
		"latex": "",
		"text":  "",
		"float": "",
		"error": "",
	}
	c.Data["json"] = result
	defer func() {
		err := recover()
		if nil != err {
			result["error"] = err
			c.ServeJSON()
		}
	}()
	request_data := auth.HandleLogin(c.Ctx.Input.RequestBody)
	request_data_json := utils.MapToJsonStr(request_data)
	username := request_data["userName"].(string)
	request_data_redis, err := db.RedisGet("EqCalc-" + request_data_json)
	curTime := utils.GetCurTimeStr()
	if nil != err {
		panic(fmt.Sprintf("%s", err))
	} else if request_data_redis != "" {
		resp_result_redis := utils.JsonStrToMap(request_data_redis)
		db.EsInsert("math_calc_index", "eq_calc_records", curTime+"_"+username, request_data_redis)
		c.Data["json"] = resp_result_redis
		c.ServeJSON()
		return
	}
	resp_data := requests.Post(source.Src.GetFlaskUrl()+"/eq_calc", request_data, map[string]interface{}{"timeout": 300})
	beego.Info("fastapi响应: ", resp_data)
	resp_result := utils.JsonStrToMap(resp_data)
	_, err = db.RedisSet("EqCalc-"+request_data_json, resp_data)
	if err != nil {
		panic(fmt.Sprintf("%s", err))
	}
	resp_result["username"] = username
	delete(request_data, "userName")
	delete(request_data, "loginID")
	data_map := map[string]interface{}{
		"request":     request_data,
		"response":    resp_result,
		"create_time": curTime,
	}
	datajson := utils.MapToJsonStr(data_map)
	db.EsInsert("math_calc_index", "eq_calc_records", curTime+"_"+username, datajson)
	c.Data["json"] = resp_result
	c.ServeJSON()
	beego.Info("================= EqCalc end =================")
}

func (c *MathCalcController) DelEqCalcRecords() {
	beego.Info("================= DelEqCalcRecords start =================")
	result := map[string]interface{}{
		"status": true,
		"error":  "",
	}
	c.Data["json"] = result
	defer func() {
		err := recover()
		if nil != err {
			result["status"] = false
			result["error"] = err
			c.ServeJSON()
		}
	}()
	request_data := auth.HandleLogin(c.Ctx.Input.RequestBody)
	records := utils.CheckFieldExists(request_data, "record").([]interface{})
	for _, esid := range records {
		db.EsDelete("math_calc_index", "eq_calc_records", esid.(string))
	}
	c.ServeJSON()
	beego.Info("================= DelEqCalcRecords end =================")
}

func (c *MathCalcController) QueryEqCalcRecords() {
	beego.Info("================= QueryEqCalcRecords start =================")
	result := map[string]interface{}{
		"data":  "",
		"count": 0,
		"error": "",
	}
	c.Data["json"] = result
	defer func() {
		err := recover()
		if nil != err {
			result["error"] = err
			c.ServeJSON()
		}
	}()
	request_data := auth.HandleLogin(c.Ctx.Input.RequestBody)
	es_info := source.Src.GetEsInfo()
	beego.Info(es_info)
	var es_auth = map[string]string{
		"username": es_info["usr"],
		"password": es_info["pwd"],
	}
	scroll_id := utils.CheckFieldExists(request_data, "scroll_id").(string)
	scroll_time := utils.CheckFieldExists(request_data, "scroll_time").(string)
	beego.Info("Restful查询ES")
	if scroll_id != "" {
		scroll_query := map[string]string{
			"scroll_id": scroll_id,
			"scroll":    scroll_time,
		}
		beego.Info("ES scroll 查询")
		resp_scroll_data := requests.Post(
			source.Src.GetEsUrl()+"/_search/scroll",
			scroll_query, map[string]interface{}{"auth": es_auth})
		resp_scroll_data_map := make(map[string]interface{})
		json.Unmarshal([]byte(resp_scroll_data), &resp_scroll_data_map)
		scroll_error := utils.GetDefault(resp_scroll_data_map, "error", "")
		if scroll_error == "" {
			data_result_, count_, scroll_data_id_ := handleESdata(resp_scroll_data_map)
			result["data"] = data_result_
			result["count"] = count_
			result["scroll_id"] = scroll_data_id_
			c.ServeJSON()
			return
		}
	}
	username := request_data["userName"].(string)
	var must_query []interface{}
	must_query = append(must_query, map[string]interface{}{
		"nested": map[string]interface{}{
			"path": "response",
			"query": map[string]map[string]string{
				"match": {
					"response.username": username,
				},
			},
		},
	})
	expr := utils.CheckFieldExists(request_data, "expr").(string)
	beego.Info("expr: ", expr)
	if expr != "" {
		must_query = append(must_query, map[string]interface{}{
			"nested": map[string]interface{}{
				"path": "request",
				"query": map[string]map[string]string{
					"match": {
						"request.expr": expr,
					},
				},
			},
		})
	}
	unns := utils.CheckFieldExists(request_data, "unns").([]interface{})
	beego.Info("unns: ", unns)
	unns_str := ""
	for _, value := range unns {
		unns_str += value.(string) + " "
	}
	if len(unns) != 0 {
		must_query = append(must_query, map[string]interface{}{
			"nested": map[string]interface{}{
				"path": "request",
				"query": map[string]map[string]string{
					"match": {
						"request.unns": unns_str,
					},
				},
			},
		})
	}
	latex := utils.CheckFieldExists(request_data, "latex").(string)
	beego.Info("latex: ", latex)
	if latex != "" {
		must_query = append(must_query, map[string]interface{}{
			"nested": map[string]interface{}{
				"path": "response",
				"query": map[string]map[string]string{
					"match": {
						"response.latex": latex,
					},
				},
			},
		})
	}
	text := utils.CheckFieldExists(request_data, "text").(string)
	beego.Info("text: ", text)
	if text != "" {
		must_query = append(must_query, map[string]interface{}{
			"nested": map[string]interface{}{
				"path": "response",
				"query": map[string]map[string]string{
					"match": {
						"response.text": text,
					},
				},
			},
		})
	}
	float_ := utils.CheckFieldExists(request_data, "float").(string)
	beego.Info("float: ", float_)
	if float_ != "" {
		must_query = append(must_query, map[string]interface{}{
			"nested": map[string]interface{}{
				"path": "response",
				"query": map[string]map[string]string{
					"match": {
						"response.float": float_,
					},
				},
			},
		})
	}
	time_range := utils.CheckFieldExists(request_data, "time").([]interface{})
	beego.Info("time: ", time_range)
	date_low := strings.Trim(time_range[0].(string), " ")
	date_high := strings.Trim(time_range[1].(string), " ")
	if date_low != "" {
		must_query = append(must_query, map[string]map[string]map[string]string{
			"range": {
				"create_time": {
					"gte":    date_low,
					"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis",
				},
			},
		})
	}
	if date_high != "" {
		must_query = append(must_query, map[string]map[string]map[string]string{
			"range": {
				"create_time": {
					"lte":    date_high,
					"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis",
				},
			},
		})
	}
	size := utils.CheckFieldExists(request_data, "size").(float64)
	beego.Info("size: ", size)
	var query = map[string]interface{}{
		"query": map[string]interface{}{
			"bool": map[string]interface{}{
				"must": must_query,
			},
		},
		"size": size,
		"sort": []map[string]map[string]string{
			{
				"create_time": {
					"order": "desc",
				},
			},
		},
	}
	resp_data := requests.Post(
		source.Src.GetEsUrl()+"/math_calc_index/eq_calc_records/_search?scroll="+scroll_time,
		query, map[string]interface{}{"auth": es_auth})
	resp_data_map := make(map[string]interface{})
	json.Unmarshal([]byte(resp_data), &resp_data_map)
	data_result, count, scroll_data_id := handleESdata(resp_data_map)
	result["data"] = data_result
	result["count"] = count
	result["scroll_id"] = scroll_data_id
	c.ServeJSON()
	beego.Info("================= QueryEqCalcRecords end =================")
}

func handleESdata(data map[string]interface{}) ([]interface{}, int, string) {
	scroll_data_id := utils.GetDefault(data, "_scroll_id", "").(string)
	hits_outside := utils.CheckFieldExists(data, "hits").(map[string]interface{})
	count := int(hits_outside["total"].(float64))
	hits_inside, _ := hits_outside["hits"].([]interface{})
	data_result := []interface{}{}
	for _, value := range hits_inside {
		_value := value.(map[string]interface{})
		_id := _value["_id"].(string)
		_source := _value["_source"].(map[string]interface{})
		_request := _source["request"].(map[string]interface{})
		_response := _source["response"].(map[string]interface{})
		_result := map[string]interface{}{}
		_result["id"] = _id
		_result["expr"] = _request["expr"]
		_result["unns"] = _request["unns"]
		_result["latex"] = _response["latex"]
		_result["text"] = _response["text"]
		_result["float"] = _response["float"]
		_result["create_time"] = _source["create_time"]
		data_result = append(data_result, _result)
	}
	return data_result, count, scroll_data_id
}
